﻿using gt.IdentityServer.Data;
using IdentityModel;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace gt.IdentityServer.Services.Impl
{
    public class LoginService : ILoginService
    {
        private AppIdentityContext _context;

        public LoginService(AppIdentityContext context)
        {
            _context = context;
        }

        public async Task<AppUser> FindLoginUserAsync(string userName, string password)
        {
            return await _context.Users.AsNoTracking()
                .Include(user => user.Group)
                .FirstOrDefaultAsync(x => x.UserName == userName && x.Password == password);
        }

        public async Task<AppUser> FindUserInfoByIdAsync(int userId)
        {
            return await _context.Users.AsNoTracking()
                .Include(user => user.Group)
                    .ThenInclude(group => group.RoleMappings)
                        .ThenInclude(roleMapping => roleMapping.Role)
                .Include(user => user.RoleMappings)
                    .ThenInclude(roleMapping => roleMapping.Role)
                .AsSingleQuery()
                .SingleOrDefaultAsync(user => user.Id == userId);
        }

        public List<AppUserRole> GetRolesByUser(AppUser user)
        {
            if (user == null) return null;
            List<AppUserRole> roles = new List<AppUserRole>();
            if (user.RoleMappings != null)
                roles.AddRange(user.RoleMappings.Select(x => x.Role));
            if (user.Group != null && user.Group.RoleMappings != null)
            {
                var temp = user.Group.RoleMappings.Select(x => x.Role);
                foreach (var r in temp)
                {
                    if (!roles.Any(x => x.Id == r.Id))
                    {
                        roles.Add(r);
                    }
                }
            }

            return roles;
        }

        public IEnumerable<Claim> GetClaims(AppUser user)
        {
            var claims = new List<Claim> {
                new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
                new Claim(JwtClaimTypes.Gender,user.Gender.ToString()),
                new Claim("username",user.UserName),
                new Claim("showname",user.ShowName),
                new Claim("age",user.Age.ToString()),
                new Claim("group",user.Group?.Name)
            };
            var roles = GetRolesByUser(user);
            //todo 不支持json序列化？
            //答 entityframework 外键循环关联引用导致,反序列时，忽略loop
            //JsonConvert.SerializeObject(roles, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
            if (roles != null && roles.Any())
                claims.Add(new Claim(JwtClaimTypes.Role, string.Join(',', roles.Select(x => x.Name))));
            return claims;
        }
    }
}
